﻿package asfiles.spectrums {
	
	import flash.display.Sprite;
	import flash.display.BitmapData;
	import flash.utils.ByteArray;
	import flash.events.Event;
	import flash.display.Shape;
	import flash.geom.Point;
	import flash.filters.BlurFilter;
	import flash.display.Bitmap;
	import flash.media.SoundMixer;
	import flash.geom.ColorTransform;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.errors.EOFError;
	import flash.text.TextField;
	import asfiles.interfaces.IVSpectrum;
	import flash.text.TextFieldAutoSize;

	public class SmoothSpectrum extends Sprite implements IVSpectrum 
	
	{
		
		// data members
		private var nAmp:int;
		private var myBytes:ByteArray;
		private var myPoints:Array;
		private var arrayMidpoints:Array;
		private var colors:Array;
		private var ratios:Array;
		private var alphas:Array;
		private var matrix:Matrix;
		private var blendArray:Array;
		private var blendStyle:String;
		
		// graphic members
		private var myCurve:Shape;
		private var myScreen:BitmapData;
		private var myPoint:Point;
		private var myBlur:BlurFilter;
		private var myColorTrans:ColorTransform;
		private var displace:Matrix;
		private var mouseDown:Boolean;
		
		public function SmoothSpectrum ( pWidth:Number , pHeight:Number, pAmplitude:int ) {
			
			var myLegende:TextField = new TextField();
			
			myLegende.autoSize = TextFieldAutoSize.LEFT;
			
			myLegende.selectable = false;
			
			myLegende.textColor = 0x777777;
			
			myLegende.text = "bezier computeSpectrum() - bytearray.org";
						
			myLegende.x = 260, myLegende.y = 375;
			
			////////////////////////////////// GRAPHICS STUFF
			// our bitmap screen, where the curves are drawn
			myScreen = new BitmapData ( pWidth, pHeight, true, 0 );
			
			// default blendMode
			blendStyle = 'normal';
			
			// screen is blurred !!
			// using multiple of 2 increases performance by 40%
			myBlur = new BlurFilter ( 2, 2, 2 );
			
			// colorTransformation
			myColorTrans = new ColorTransform ();
			
			myColorTrans.color = Math.random()*0xFFFFFF;
			
			// add it to the displayList
			addChild ( new Bitmap ( myScreen ) );
			
			addChild ( myLegende );
			
			// DATA STUFF
			// byteArray to hold frequencies
			myBytes = new ByteArray();
			
			//rotate it	
			displace = new Matrix();
			//displace.scale (.5, .5);
			
			blendArray = ['layer', 'multiply', 'screen', 'lighten', 'darken',
						  'difference', 'add', 'subtract', 'invert', 'alpha', 'erase', 
						  'overlay', 'hardlight' ];
			
			// points holder
			myPoints = new Array();
			
			// midpoints holder
			arrayMidpoints = new Array();
			
			// set the wavin' amplitude
			nAmp = pAmplitude;
			
			// the curve to draw the spectrum
			myCurve = new Shape();
			
			// the point
			myPoint = new Point ( 0, 0 );
			
			// setup color gradients
			colors = [0x990000, 0x00FF00];
			alphas = [100, 100];
			ratios = [80, 255];
			matrix = new Matrix();
			matrix.createGradientBox ( 850, 1, 0, 0, 0);
			
			addEventListener (Event.ADDED, onAdded);
			
		}
		
		private function onAdded ( pEvt:Event ):void 
		
		{
			
			addEventListener (Event.ENTER_FRAME, updatePoints);
						
			addEventListener ( Event.REMOVED, onRemoved );
			
			stage.addEventListener (MouseEvent.MOUSE_DOWN, onClick );
			
		}
			
		public function onRemoved( pEvt:Event ):void 
		
		{
			
			myScreen.dispose();
			
			removeEventListener (Event.ENTER_FRAME, updatePoints );
			
			stage.removeventListener (MouseEvent.MOUSE_DOWN, onClick );
			
		}
		
		private function updatePoints ( pEvt:Event ):void {
			
			// clear each frame
			myCurve.graphics.clear();
			
			myCurve.graphics.lineStyle (.01);
			
			// apply gradient to the line
			myCurve.graphics.lineGradientStyle ( 'linear', colors, alphas, ratios, matrix, 'pad', 'linearRGB', 0.1);
			
			// generate the ByteArray
			SoundMixer.computeSpectrum ( myBytes, mouseDown );
			
			// 32 loops to draw 32 points, and get 32 frequencies
			// in the wole byteArray ( 16 * 128 = 2048 )
			// a float (32bit) = 4 bytes so 512 float = 512 * 4 = 2048
			
			var i:int = 16;
			
			try {
			
				while ( --i > -1 ) {
															
					// change the position of the pointer
					myBytes.position = i * 128;
					
					// get frequency
					var offset:Number = myBytes.readFloat()*nAmp;
					
					// create a point object
					// y is related to the offset
					var myObj:Object = { x : 60 + ( 40 * i ), y : 200 + (-offset) };		
					
					// push each points 
					myPoints[i] = myObj;
	
					
				}
				
			} catch ( err:EOFError ) {
				
				trace("you've gone too far")
				
			}
			
			// now generate a mid-point array
			// to make those mid-points the curve anchor points
			for (var j:int = 1; j< myPoints.length; j++ ) {
				
				var midPointX:Number = ( myPoints[j].x + myPoints[j-1].x )/2
				var midPointY:Number = ( myPoints[j].y + myPoints[j-1].y )/2
				
				var midPointsObj:Object = { x : midPointX, y : midPointY };
				
				arrayMidpoints[j-1] = midPointsObj;

			}
			
			//myScreen.colorTransform (myScreen.rect, myColorTrans);
			
			//myCurve.graphics.beginGradientFill  ('linear', colors, alphas, ratios, matrix, 'pad', 'linearRGB', 0.9);
			
			myCurve.graphics.moveTo ( arrayMidpoints[0].x, arrayMidpoints[0].y );
			
			// make the curve start at the first mid-point location
			
			// then draw the curve
			for (var k:int = 1; k< myPoints.length-1; k++ ) {

				myCurve.graphics.curveTo ( myPoints[k].x, myPoints[k].y, arrayMidpoints[k].x, arrayMidpoints[k].y );
				
			}
			
			// scroll the bitmap
			myScreen.scroll ( 1, 0 );

			// draw curve vectors on the BitmapData
			myScreen.draw ( myCurve, null, null, "add" );
			
			myScreen.applyFilter ( myScreen, myScreen.rect, myPoint, myBlur );
			
		}
		
		private function onClick ( pEvt:MouseEvent ):void {
			
			blendStyle = blendArray [ Math.floor ( Math.random()* blendArray.length ) ];
			
			colors = [Math.random()*0xFFFFFF, Math.random()*0xFFFFFF];
			
			mouseDown = !mouseDown
			
		}
		
		// INTERFACE IMPLEMENTATION
		
		public function move ( pX:Number, pY:Number ):void
		
		{
			
			this.x = pX, this.y = pY;
			
		}
		
	}
}